// $Id: test_char_traits.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2008 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#define BOOST_TEST_MODULE test_char_traits
#include <cstddef>
#include <boost/test/unit_test.hpp>
#include <xpcom/char_traits.hpp>
#include <xpcom/string.hpp>

BOOST_AUTO_TEST_CASE(test_char)
{
  const xpcom::string str_01("zuma beach");
  const xpcom::string str_02("montara and ocean beach");

  // 21.1.1 character traits requirements

  // Key for decoding what function signatures really mean:
  // X        == char_traits<_CharT>
  // [c,d]    == _CharT
  // [p,q]    == const _CharT*
  // s        == _CharT*
  // [n,i,j]  == std::size_t
  // f        == X::int_type
  // pos      == X::pos_type
  // state    == X::state_type

  // void X::assign(char c, char d)
  // assigns c = d;
  char c1 = 'z';
  char c2 = 'u';
  BOOST_CHECK( c1 != c2 );
  xpcom::char_traits<char>::assign(c1,c2);
  BOOST_CHECK( c1 == 'u' );

  // char* X::move(char* s, const char* p, std::size_t n)
  // for each i in [0,n) performs X::assign(s[i], p[i]). Copies
  // correctly even where p is in [s, s + n), and yields s.
  char array1[] = {'z', 'u', 'm', 'a', ' ', 'b', 'e', 'a', 'c', 'h',  0};
  const char str_lit1[] = "montara and ocean beach";
  const char str_lit2[] = "boracay, philippines";
  const int len1 = sizeof(str_lit1)/sizeof(char);
  const int len2 = sizeof(str_lit2)/sizeof(char);
  char array2[len1 + len2 - 1]; // two terminating chars
  xpcom::char_traits<char>::copy(array2, str_lit2, len2);

  BOOST_CHECK( str_lit1[0] == 'm' );
  c1 = array2[0];
  c2 = str_lit1[0];
  char c3 = array2[1];
  char c4 = str_lit1[1];
  xpcom::char_traits<char>::move(array2, str_lit1, 0);
  BOOST_CHECK( array2[0] == c1 );
  BOOST_CHECK( str_lit1[0] == c2 );
  xpcom::char_traits<char>::move(array2, str_lit1, 1);
  BOOST_CHECK( array2[0] == c2 );
  BOOST_CHECK( str_lit1[0] == c2 );
  BOOST_CHECK( array2[1] == c3 );
  BOOST_CHECK( str_lit1[1] == c4 );
  xpcom::char_traits<char>::move(array2, str_lit1, 2);
  BOOST_CHECK( array2[0] == c2 );
  BOOST_CHECK( str_lit1[0] == c2 );
  BOOST_CHECK( array2[1] == c4 );
  BOOST_CHECK( str_lit1[1] == c4 );

  char* pc1 = array1 + 1;
  c1 = pc1[0];
  c2 = array1[0];
  BOOST_CHECK( c1 != c2 );
  char* pc2 = xpcom::char_traits<char>::move(array1, pc1, 0);
  c3 = pc1[0];
  c4 = array1[0];
  BOOST_CHECK( c1 == c3 );
  BOOST_CHECK( c2 == c4 );
  BOOST_CHECK( pc2 == array1 );

  c1 = pc1[0];
  c2 = array1[0];
  char* pc3 = pc1;
  pc2 = xpcom::char_traits<char>::move(array1, pc1, 10);
  c3 = pc1[0];
  c4 = array1[0];
  BOOST_CHECK( c1 != c3 ); // underlying char array changed.
  BOOST_CHECK( c4 != c3 );
  BOOST_CHECK( pc2 == array1 );
  BOOST_CHECK( pc3 == pc1 ); // but pointers o-tay
  c1 = *(str_01.data());
  c2 = array1[0];
  BOOST_CHECK( c1 != c2 );
}

#ifdef XPCOM_HAS_2BYTE_WCHAR_T

BOOST_AUTO_TEST_CASE(test_wchar)
{
  using namespace xpcom;
  const xpcom::wstring str_01(L"zuma beach");
  const xpcom::wstring str_02(L"montara and ocean beach");

  // 21.1.1 character traits requirements

  // Key for decoding what function signatures really mean:
  // X        == char_traits<_CharT>
  // [c,d]    == _CharT
  // [p,q]    == const _CharT*
  // s        == _CharT*
  // [n,i,j]  == std::size_t
  // f        == X::int_type
  // pos      == X::pos_type
  // state    == X::state_type

  // void X::assign(wchar_t c, wchar_t d)
  // assigns c = d;
  wchar c1 = L'z';
  wchar c2 = L'u';
  BOOST_CHECK( c1 != c2 );
  xpcom::char_traits<wchar>::assign(c1,c2);
  BOOST_CHECK( c1 == L'u' );

  // char* X::move(char* s, const char* p, std::size_t n)
  // for each i in [0,n) performs X::assign(s[i], p[i]). Copies
  // correctly even where p is in [s, s + n), and yields s.
  wchar array1[] = {L'z', L'u', L'm', L'a', L' ', L'b', L'e', L'a', L'c', L'h',  0};
  const wchar str_lit1[] = L"montara and ocean beach";
  const wchar str_lit2[] = L"boracay, philippines";
  const int len1 = sizeof(str_lit1)/sizeof(wchar);
  const int len2 = sizeof(str_lit2)/sizeof(wchar);
  wchar array2[len1 + len2 - 1]; // two terminating chars
  xpcom::char_traits<wchar>::copy(array2, str_lit2, len2);

  BOOST_CHECK( str_lit1[0] == 'm' );
  c1 = array2[0];
  c2 = str_lit1[0];
  wchar c3 = array2[1];
  wchar c4 = str_lit1[1];
  xpcom::char_traits<wchar>::move(array2, str_lit1, 0);
  BOOST_CHECK( array2[0] == c1 );
  BOOST_CHECK( str_lit1[0] == c2 );
  xpcom::char_traits<wchar>::move(array2, str_lit1, 1);
  BOOST_CHECK( array2[0] == c2 );
  BOOST_CHECK( str_lit1[0] == c2 );
  BOOST_CHECK( array2[1] == c3 );
  BOOST_CHECK( str_lit1[1] == c4 );
  xpcom::char_traits<wchar>::move(array2, str_lit1, 2);
  BOOST_CHECK( array2[0] == c2 );
  BOOST_CHECK( str_lit1[0] == c2 );
  BOOST_CHECK( array2[1] == c4 );
  BOOST_CHECK( str_lit1[1] == c4 );

  wchar* pc1 = array1 + 1;
  c1 = pc1[0];
  c2 = array1[0];
  BOOST_CHECK( c1 != c2 );
  wchar* pc2 = xpcom::char_traits<wchar>::move(array1, pc1, 0);
  c3 = pc1[0];
  c4 = array1[0];
  BOOST_CHECK( c1 == c3 );
  BOOST_CHECK( c2 == c4 );
  BOOST_CHECK( pc2 == array1 );

  c1 = pc1[0];
  c2 = array1[0];
  wchar* pc3 = pc1;
  pc2 = xpcom::char_traits<wchar>::move(array1, pc1, 10);
  c3 = pc1[0];
  c4 = array1[0];
  BOOST_CHECK( c1 != c3 ); // underlying wchar array changed.
  BOOST_CHECK( c4 != c3 );
  BOOST_CHECK( pc2 == array1 );
  BOOST_CHECK( pc3 == pc1 ); // but pointers o-tay
  c1 = *(str_01.data());
  c2 = array1[0];
  BOOST_CHECK( c1 != c2 );
}

#endif // XPCOM_HAS_2BYTE_WCHAR_T
